﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing.Imaging;
using System.Drawing;

namespace RyijyApp
{
    class RyijyPng
    {
        const int MAXCHUNKSIZE = 100000;
        Bitmap image = null;
        public Bitmap Image { get { return image; } set { image = value; } }


        CustomPalette palette = null;
        public CustomPalette Palette { get { return palette; } set { palette = value; } }

        private Byte[] rsDp = new Byte[4] { 114, 115, 68, 112 };
        public Byte[] RyijyChunk { get { return rsDp; } }

        public void Save(string filename)
        {
            if (image == null) return;

            using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Create))
            {
                image.Save(fs, ImageFormat.Png);
                if (palette != null)
                {
                    System.IO.StringWriter wr = new System.IO.StringWriter();
                    wr.WriteLine("1");
                    wr.WriteLine(palette.PaletteName);
                    palette.Save(wr);
                    byte[] chunkdata = System.Text.Encoding.UTF8.GetBytes(wr.ToString());
                    // Chunk: <LEND><rsDp><DATA><CRC4>
                    byte[] chunk = new byte[12+chunkdata.Length];
                    chunk[0] = Convert.ToByte(0xff & (chunkdata.Length >> 24));
                    chunk[1] = Convert.ToByte(0xff & (chunkdata.Length >> 16));
                    chunk[2] = Convert.ToByte(0xff & (chunkdata.Length >> 8));
                    chunk[3] = Convert.ToByte(0xff & (chunkdata.Length));
                    rsDp.CopyTo(chunk, 4);
                    chunkdata.CopyTo(chunk, 8);
                    Crc32 crc32 = new Crc32();
                    crc32.InsertCrcToEnd(chunk, 4);

                    // remove endchunk and write own chunk
                    long pos = fs.Position;
                    fs.Position = pos - 12;
                    fs.Write(chunk, 0, chunk.Length);

                    // Write end chunk again
                    byte[] endchunk = new byte[] { 00, 00, 00, 00, 0x49, 0x45, 0x4E, 0x44, 0xAE, 0x42, 0x60, 0x82 };
                    fs.Write(endchunk, 0, endchunk.Length);
                }
            }
        }
        public bool IsMyChunk(byte[] buf, int offset)
        {
            if (buf.Length < offset + 4) return false;
            for (int i = 0; i < 4; i++)
                if (rsDp[i] != buf[offset + i]) return false;
            return true;
        }
        public void Load(string filename)
        {
            using (System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open))
            {
                image  = new Bitmap(fs);

                // Search for our chunk
                bool chunkFound = false;
                int offset = 0;
                int len = 0;
                byte[] buf = new byte[8];

                // Check header
                fs.Seek(offset, System.IO.SeekOrigin.Begin);
                if (fs.Read(buf, 0, 8) != 8 ||
                    buf[0] != 0x89 )
                {
                    // no valid palette found
                    palette = null;
                    return;
                }
                offset = 8;

                while (!chunkFound)
                {
                    fs.Seek(offset, System.IO.SeekOrigin.Begin);
                    if (fs.Read(buf, 0, 8) != 8)
                    {
                        // no valid palette found
                        palette = null;
                        return;
                    }
                    len  = buf[0] << 24;
                    len += buf[1] << 16;
                    len += buf[2] << 8;
                    len += buf[3];
                    if (IsMyChunk(buf, 4))
                        chunkFound = true;
                    else if (len >= 0)
                    {
                        offset += len + 12;
                    }
                    else
                    {
                        throw new System.Exception("Invalid Ryijy Stitch Designer file");
                    }
                }
                if (chunkFound && len >0 && len < MAXCHUNKSIZE)
                {
                    // Load palette
                    byte[] chunk = new byte[len];
                    fs.Read(chunk, 0, len);
                    System.IO.StringReader sr = new System.IO.StringReader(System.Text.Encoding.UTF8.GetString(chunk));
                    palette = new CustomPalette();
                    string version = sr.ReadLine();
                    if (version != "1")
                        throw new System.Exception("Invalid Ryijy Stitch Designer file");
                    palette.PaletteName = sr.ReadLine();
                    palette.Load(sr);



                }
            }

        }
    }
}
